/*
 * @文件描述:初始化系统，初始化各个线程，线程的管理
 * @版本:
 * @作者: 周晨阳
 * @Date: 2021-01-13 21:43:10
 * test1 from laptop,
 * test2 from laptop.
 */
 /* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "GUI.h"
#include "LED.h"
#include "TFT.h"
#include "usart.h"
#include <rtthread.h>
#include "myADC.h"
#include "OscilloscopeUICodes.h"
#include "mySRAM.h"
#include "myButton.h"
#include "OscilloscopePre.h"
#include "multiMeter.h"
#include "MultiMeterPre.h"
#include "oscilloscope.h"
#include "beeper.h"
#include "sigGenerator.h"
// #include "filter.h"
#include "homePage.h"
#include "HomePagePre.h"
#include "board.h"
#include "public.h"
#include "lvgl/lvgl.h"
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include <SDL.h>
#include "lvgl/examples/lv_examples.h"
#include "lv_examples/lv_demo.h"
#include "lv_drivers/display/monitor.h"
#include "lv_drivers/indev/mouse.h"
#include "lv_drivers/indev/keyboard.h"
#include "lv_drivers/indev/mousewheel.h"

//#include "exfuns.h"
#include "delay.h"
//#include "fontupd.h"
//#include "fattester.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/

static struct rt_thread LEDThread_ptr;
static rt_uint8_t LEDThread_stack[400];

static struct rt_thread TFTThread_ptr;
static rt_uint8_t TFTThread_stack[3000];

static struct rt_thread touchScreenThread_ptr;
static rt_uint8_t touchScreenThread_stack[600];

static struct rt_thread systestThread_ptr;
static rt_uint8_t systestThread_stack[100];

static struct rt_thread buttonThread_ptr;
static rt_uint8_t buttonThread_stack[80];

static struct rt_thread oscillThread_ptr;
static rt_uint8_t oscillThread_stack[5000];

static struct rt_thread multiMeterThread_ptr;
static rt_uint8_t multiMeterThread_stack[120];

static struct rt_mutex lvglMutex;
static int Fps = 0;
static uint8_t touchFreashRate = 0;

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
extern int rt_application_init(void);
extern rt_uint8_t* heap;
extern int platform_init(void);
extern int platform_post_init(void);
extern int mnt_init(void);

static void rtthread_startup(void)
{
    /* init board */
    rt_hw_board_init();

    /* show version */
    rt_show_version();

    /* init tick */
    rt_system_tick_init();

    /* init kernel object */
    rt_system_object_init();

    /* init timer system */
    rt_system_timer_init();

#ifdef RT_USING_HEAP
    /* init memory system */
    rt_system_heap_init((void*)heap, (void*)&heap[RT_HEAP_SIZE - 1]);
#endif

    /* init scheduler system */
    rt_system_scheduler_init();

    /* init application */
    rt_application_init();

    /* init timer thread */
    rt_system_timer_thread_init();

    /* init idle thread */
    rt_thread_idle_init();

    /* start scheduler */
    rt_system_scheduler_start();

    /* never reach here */
    return;
}
/**
 * @brief : 打印线程的状态
 * @param {struct rt_thread} thread
 * @return {*}
 */
void printThreadState(struct rt_thread thread)
{
    printf("thread:%s, state:%d\n", thread.name, thread.stat);
}
/**
 * @brief : 打印所有线程的状态
 * @param {*}
 * @return {*}
 */
void printfAllThreadStat()
{
    printThreadState(oscillThread_ptr);
    printThreadState(touchScreenThread_ptr);
    printThreadState(buttonThread_ptr);
    printThreadState(multiMeterThread_ptr);
    printThreadState(TFTThread_ptr);
}
/**
 * @description: 实体按键扫描线程
 * @param {void} *parameter
 * @return {*}
 */
void buttonThread(void* parameter)
{
    while (1)
    {

        buttonLooper();
        //printf("button thread running\n");
        rt_thread_mdelay(40);
    }
}
/**
 * @brief : 触摸屏扫描线程
 * @param {void} *parameter
 * @return {*}
 */
void touchScreenThread(void* parameter)
{
    while (1)
    {
#ifdef GUI_UCGUI
        GUI_TOUCH_Exec(); //调用UCGUI TOUCH相关函数
#endif

    //printf("touch thread running\n");
        touchFreashRate++;
        rt_thread_mdelay(20);
    }
}
static void hal_init(void)
{
  /* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
  monitor_init();
  /* Tick init.
	 * You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about
	 * how much time were elapsed Create an SDL thread to do this*/
  //SDL_CreateThread(tick_thread, "tick", NULL);

  /*Create a display buffer*/
  static lv_disp_draw_buf_t disp_buf1;
  static lv_color_t buf1_1[MONITOR_HOR_RES * 100];
  static lv_color_t buf1_2[MONITOR_HOR_RES * 100];
  lv_disp_draw_buf_init(&disp_buf1, buf1_1, buf1_2, MONITOR_HOR_RES * 100);

  /*Create a display*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv); /*Basic initialization*/
  disp_drv.draw_buf = &disp_buf1;
  disp_drv.flush_cb = monitor_flush;
  disp_drv.hor_res = MONITOR_HOR_RES;
  disp_drv.ver_res = MONITOR_VER_RES;
  disp_drv.antialiasing = 1;

  lv_disp_t *disp = lv_disp_drv_register(&disp_drv);

  lv_theme_t *th = lv_theme_default_init(disp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), LV_THEME_DEFAULT_DARK, LV_FONT_DEFAULT);
  lv_disp_set_theme(disp, th);

  lv_group_t *g = lv_group_create();
  lv_group_set_default(g);

  /* Add the mouse as input device
	 * Use the 'mouse' driver which reads the PC's mouse*/
  mouse_init();
  static lv_indev_drv_t indev_drv_1;
  lv_indev_drv_init(&indev_drv_1); /*Basic initialization*/
  indev_drv_1.type = LV_INDEV_TYPE_POINTER;

  /*This function will be called periodically (by the library) to get the mouse position and state*/
  indev_drv_1.read_cb = mouse_read;
  lv_indev_t *mouse_indev = lv_indev_drv_register(&indev_drv_1);

  keyboard_init();
  static lv_indev_drv_t indev_drv_2;
  lv_indev_drv_init(&indev_drv_2); /*Basic initialization*/
  indev_drv_2.type = LV_INDEV_TYPE_KEYPAD;
  indev_drv_2.read_cb = keyboard_read;
  lv_indev_t *kb_indev = lv_indev_drv_register(&indev_drv_2);
  lv_indev_set_group(kb_indev, g);
  mousewheel_init();
  static lv_indev_drv_t indev_drv_3;
  lv_indev_drv_init(&indev_drv_3); /*Basic initialization*/
  indev_drv_3.type = LV_INDEV_TYPE_ENCODER;
  indev_drv_3.read_cb = mousewheel_read;

  lv_indev_t *enc_indev = lv_indev_drv_register(&indev_drv_3);
  lv_indev_set_group(enc_indev, g);

  /*Set a cursor for the mouse*/
  LV_IMG_DECLARE(mouse_cursor_icon);                  /*Declare the image file.*/
  lv_obj_t *cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */
  lv_img_set_src(cursor_obj, &mouse_cursor_icon);     /*Set the image source*/
  lv_indev_set_cursor(mouse_indev, cursor_obj);       /*Connect the image  object to the driver*/
}
#include "OscilloscopePre.h"

/**
 * @brief tft刷新线程
 * @param {void} *parameter
 * @return {*}
 */
void tftUpdateThread(void* parameter)
{
    int i;
#ifdef GUI_UCGUI
   while (1)
    {
        if (getCurrentApp() == APP_OSCILL)
        {
          V_drawOscilGraph();
        }
        else if (getCurrentApp() == APP_MULTIMETER)
        {
          V_drawNiddle();
        }

        GUI_Exec(); //调用UCGUI
#else
        lv_init();
        hal_init();
        #ifdef GUI_LVGL
        homePageInit(0);

        #endif
    while (1)
    {

        rt_mutex_take(&lvglMutex, 10);
        lv_timer_handler();
        rt_mutex_release(&lvglMutex);

#endif
        Fps++;
        // printf("tft thread running\n");
        rt_thread_mdelay(10);
    }
}
/**
 * @brief : 系统初始化线程，用于设置一些东西
 * @param {void} *p
 * @return {*}
 */
void sysStartUpThread(void* p)
{
    rt_thread_mdelay(1000);
}
/**
 * @brief : 示波器线程
 * @param {void} *p
 * @return {*}
 */
void oscillThread(void* p)
{
    while (1)
    {
        /* code */
        //printf("oscill thread running\n");
        oscillLooper();
        //printfAllThreadStat();
        rt_thread_mdelay(20);
    }
}
/**
 * @brief : 万用表更新线程
 * @param {void} *p
 * @return {*}
 */
void multiMeterThread(void* p)
{
    while (1)
    {
        /* code */
        //printf("multiMeter thread running\n");

        //MultiMeterValueUpdateLooper();
        rt_thread_mdelay(10);
    }
}
/**
 * @brief : 模块管理
 * @param {*}
 * @return {*}
 */
static void moduleManagement(uint8_t module, uint8_t state)
{
    switch (module)
    {
    case MODULE_KEYBOARD:
        if (state == DISCONNECTED)
        {
            V_goHome();
        }
        /* code */
        break;
    case MODULE_MULTIMETER:
        if (state == DISCONNECTED && getCurrentApp() == APP_MULTIMETER)
        {
            V_goHome();
        }

        /* code */
        break;
    case MODULE_OSCILL:
        if (state == DISCONNECTED && getCurrentApp() == APP_OSCILL)
        {
            V_goHome();
        }

        /* code */
        break;

    default:
        break;
    }
}
/**
 * @brief : 用于测量FPS、指示系统工作状态,每秒运行一次
 * @param {*}
 * @return {*}
 */
static void oneSecond2Cb(void* p)
{
    static rt_uint32_t total, used, max_used;

#ifdef SHOW_FPS
    printf("FPS:%d,touch:%d\n", Fps, touchFreashRate);
#endif

    Fps = 0;
    touchFreashRate = 0;
    trigLed(LED_GREEN);

#ifdef SHOW_HEAP_INFO
    rt_memory_info(&total, &used, &max_used);
    printf("mem:total:%ld,used:%ld,max:%ld\n", total, used, max_used);
#endif

    moduleChecking();
}

#ifdef GUI_LVGL
static void lv_timer(void* p)
{
    lv_tick_inc(10);
}
#endif

/**
 * @brief : 系统初始化
 * @param {*}
 * @return {*}
 */
void sysInit()
{

    //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //delay_init(144);
    //fileSystemInit();
 Lcd_Initialize();

#ifdef GUI_UCGUI
    GUI_Init();
#endif


    LED_Init();
    Touch_Init();
    //KEY_Init();
    //DSP_Init();
    Beeper_Init();
#ifdef MUTE
    beeperMute();
#endif

    // setModuleCheckingCb(moduleManagement);
}
/**
 * @brief : 线程及线程相关配件初始化,仅仅初始化，但不启动线程
 * @param {*}
 * @return {*}
 */
void threadInit()
{
    rt_err_t result;
    rt_thread_t settingPtr;
    int i = 0;

    result = rt_thread_init(
        &touchScreenThread_ptr, "touchScreenThread", touchScreenThread, RT_NULL,
        &touchScreenThread_stack[0], sizeof(touchScreenThread_stack), 1, 500);
    if (rt_thread_startup(&touchScreenThread_ptr) == RT_EOK && result == RT_EOK)
    {
      printf("touchScreenThread created\n");
    }
    else
    {
      printf("ERROR:touchScreenThread not created\n");
    }

    // result = rt_thread_init(&buttonThread_ptr, "buttonThread", buttonThread,
    //                         RT_NULL, &buttonThread_stack[0],
    //                         sizeof(buttonThread_stack), 2, 300);
    // if (rt_thread_startup(&buttonThread_ptr) == RT_EOK && result == RT_EOK)
    // {
    //   printf("buttonThread created\n");
    // }
    // else
    // {
    //   printf("ERROR:buttonThread not created\n");
    // }
    //初始化tft线程
    result = rt_thread_init(&TFTThread_ptr, "TFTThread", tftUpdateThread, RT_NULL,
        &TFTThread_stack[0], sizeof(TFTThread_stack), 2, 1000);
    //创建互斥锁
    if (rt_mutex_init(&lvglMutex, "lvglMutex,", RT_IPC_FLAG_PRIO) == RT_EOK)
    {
        printf("lvglMutex init done...\n");
    }
    else
    {
        printf("lvglMutex init failed...\n");
        while (1)
            ;
    }
    //oscillThread
    result = rt_thread_init(&oscillThread_ptr, "oscillThread", oscillThread,
                            RT_NULL, &oscillThread_stack[0],
                            sizeof(oscillThread_stack), 0, 1000);
    printf("oscillThread created\n");

    result = rt_thread_init(&multiMeterThread_ptr, "METERThread", multiMeterThread,
                            RT_NULL, &multiMeterThread_stack[0],
                            sizeof(multiMeterThread_stack), 4, 1000);
    printf("multiMeterThread created\n");
}
/**
 * @brief :线程启动
 * @param {*}
 * @return {*}
 */
void threadStart()
{
    if (rt_thread_startup(&TFTThread_ptr) == RT_EOK)
    {
        printf("TFT thread created\n");
    }
    else
    {
        printf("TFT thread failed\n");
    }
}
/**
 * @brief :定时器启动
 * @param {*}
 * @return {*}
 */
void timerStart()
{
    //1秒定时器
    rt_timer_start(
        rt_timer_create("oneSecond2",
            oneSecond2Cb,
            NULL,
            1000,
            RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_PERIODIC));

#ifdef GUI_LVGL
    //lgvl时钟信号
    rt_timer_start(
        rt_timer_create("lvTimerBeat",
            lv_timer,
            NULL,
            10,
            RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_PERIODIC));
#endif
}
/**
 * @brief : 文件系统读测试（已通过测试）
 * @param {*}
 * @return {*}
 */
void testForFATFS()
{
    //FIL fp;
    //uint8_t buf[50];

    //FRESULT res = f_open(&fp, "0:/testDir/test.txt", FA_READ);
    //if (res != FR_OK)
    //{
    //    printf("open error\n");
    //    return;
    //}
    //UINT br;
    //res = f_read(&fp, buf, 50, &br);
    //if (res != FR_OK)
    //{
    //    printf("read error\n");
    //    return;
    //}
    //printf("FATFS string is '%.*s'\n", br, buf);
    //f_close(&fp);

    ////测试文件夹
    ////mf_scan_files("0:/testDir");

    //res = f_open(&fp, "0:/bootInfo.txt", FA_READ | FA_WRITE | FA_OPEN_ALWAYS);
    //if (res != FR_OK)
    //{
    //    printf("bootInfo.txt open error!\n");
    //    return;
    //}
    //else
    //{
    //    printf("bootInfo.txt open done...\n");
    //}

    //res = f_read(&fp, buf, 20, &br);
    ////第一次创建此文件
    //if (br == 0)
    //{
    //    printf("first time booting\n");
    //    strcpy(buf, "bootTime:1;");
    //    res = f_puts(buf, &fp);
    //    if (res != FR_OK)
    //    {
    //        printf("f_puts error!\n");
    //    }
    //}
    ////
    //else
    //{
    //    //f_gets(buf, sizeof(buf) / sizeof(uint8_t), &fp);
    //    f_lseek(&fp, 0);
    //    int bootTime;
    //    char bootTimeBuf[25];
    //    char* head;
    //    char* end;
    //    res = f_read(&fp, buf, 25, &br);
    //    if (res != FR_OK)
    //    {
    //        printf("read bootTime error!\n");
    //    }
    //    printf("%.*s \n", br, buf);
    //    //找出：后面的字符串
    //    head = strchr(buf, ':');
    //    if (head != NULL)
    //    {
    //        strncpy(bootTimeBuf, head + 1, 4);
    //        //找到尾部的;字符，并直接置0
    //        end = strchr(bootTimeBuf, ';');
    //        if (end != NULL)
    //        {
    //            *end = '\0';
    //            bootTime = atoi(bootTimeBuf);
    //            printf("boot time num:%d\n", bootTime);
    //            bootTime++;
    //            sprintf(bootTimeBuf, "bootTime:%d;", bootTime);
    //            f_lseek(&fp, 0);
    //            res = f_write(&fp, bootTimeBuf, strlen(bootTimeBuf), &br);
    //            if (res != FR_OK)
    //            {
    //                printf("writing boot time error!\n");
    //            }
    //        }
    //    }
    //}

    //f_close(&fp);
}
/**
 * @brief : LVGL文件系统读测试
 * @param {*}
 * @return {*}
 */
void testForLvglFS()
{
    //lv_fs_file_t f;
    //lv_fs_res_t res;
    //res = lv_fs_open(&f, "0:/testDir/test.txt", LV_FS_MODE_RD);
    //if (res != LV_FS_RES_OK)
    //{
    //    printf("open error\n");
    //}

    //uint32_t read_num;
    //uint8_t buf[30];
    //res = lv_fs_read(&f, buf, 30, &read_num);
    //if (res != LV_FS_RES_OK)
    //{
    //    printf("read error\n");
    //}
    //else
    //{
    //    printf("LVGL test string is  %.*s\n", read_num, buf);
    //}

    //lv_fs_close(&f);

    ////测试读取文件夹
    //lv_fs_dir_t dir;
    //res = lv_fs_dir_open(&dir, "0:/testDir");
    //if (res != LV_FS_RES_OK)
    //{
    //    printf("lvgl open dir error\n");
    //    return;
    //}
    //else
    //{
    //    printf("lvgl open dir done...\n");
    //}

    //char fn[10 * 2 + 1];
    //while (1)
    //{
    //    res = lv_fs_dir_read(&dir, fn);
    //    if (res != LV_FS_RES_OK)
    //    {
    //        printf("read dir error\n");
    //        return;
    //        break;
    //    }

    //    /*fn is empty, if not more files to read*/
    //    if (strlen(fn) == 0)
    //    {
    //        break;
    //    }

    //    printf("%s\n", fn);
    //}

    //lv_fs_dir_close(&dir);
}
void loadFont()
{
   // updata_fontx(0, 0, 0, "0:/font/myFont.bin", 4);
}
void rt_init_thread_entry(void *parameter)
{
  rt_kprintf("Hello RT-Thread!\n");

  platform_init();
  mnt_init();

  platform_post_init();

#if defined(PKG_USING_GUIENGINE) && defined(GUIENGINE_USING_DEMO)
  {
    extern int rt_gui_demo_init(void);
    rt_gui_demo_init();
  }
#endif
}
static void mkdir_sample(void)
{
  int ret;

  /* 创建目录 */
  ret = mkdir("/dir_test", 0x777);
  if (ret < 0)
  {
    /* 创建目录失败 */
    rt_kprintf("dir error!\n");
  }
  else
  {
    /* 创建目录成功 */
    rt_kprintf("mkdir ok!\n");
  }
}
/**
 * A task to measure the elapsed time for LVGL
 * @param data unused
 * @return never return
 */
static void lvglTimer(void *data)
{

  lv_tick_inc(10); /*Tell LittelvGL that 5 milliseconds were elapsed*/
}

int rt_application_init(){
    
    rt_thread_t tid;
    tid = rt_thread_create("init",
                         rt_init_thread_entry, RT_NULL,
                         2048, RT_THREAD_PRIORITY_MAX / 3, 20);

    if (tid != RT_NULL)
    rt_thread_startup(tid);
    sysInit();
    //testForFATFS();
    //testForLvglFS();
    //loadFont();
    #ifdef GUI_UCGUI
    homePageInit(0);
    #endif
    //线程和定时器的初始化一定要放在最后，否则会出错
    threadInit();

    threadStart();

    timerStart();
    return 0;

}

/**
 * @brief : main函数
 * @param {*}
 * @return {*}
 */
void main(void)
{
   rtthread_startup();

}

/**
 * @brief : 启动示波器线程
 * @param {*}
 * @return {*}
 */
void startOscillThread()
{
    rt_thread_startup(&oscillThread_ptr);
    printf("oscillThread started\n");
}
/**
 * @brief : 删除示波器应用线程，再次启动无需重新初始化
 * @param {*}
 * @return {*}
 */
void killOscillThread()
{
    closeOscil();
    rt_thread_delete(&oscillThread_ptr);
    printf("OscillThread deleted\n");
}
/**
 * @brief : 启动万用表线程
 * @param {*}
 * @return {*}
 */
void startMultiMeterThread()
{
    rt_thread_startup(&multiMeterThread_ptr);
    printf("multiMeterThread started\n");
}
/**
 * @brief : 删除万用表线程，再次启动无需重新初始化
 * @param {*}
 * @return {*}
 */
void killMultiMeterThread()
{
    closeMultiMeter();
    //rt_thread_delete(&multiMeterThread_ptr);
    printf("multiMeterThread deleted\n");
}
